﻿using SuperSocket.Client;
using SuperSocket.ProtoBase;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IndustrialCommunication.Client
{
    class FinsTcp:EasyClient<FinsTcpPackage>
    {
        public FinsTcp():base(new FinsTcpPackageFilter())
        {
        }
        //public async Task<bool> InitializeConnect(EndPoint endPoint,CancellationToken token)
        //{
        //    var connectResult=await base.ConnectAsync(endPoint,token);
        //    if (!connectResult)return false;
        //    var sendResult = await base.SendAsync<FinsTcpPackage>();

        //}
    }
    public enum FinsTcpType
    {
        Request=0,
        Response=1,
        Work=2
    }
    public enum FinsCommandType
    {
        /// <summary>
        /// 读取命令
        /// </summary>
        Read=257,
        /// <summary>
        /// 写入命令
        /// </summary>
        Write=258
    }
    public enum FinsMemoryArea
    {
        /// <summary>
        /// 0x30
        /// </summary>
        CioBit=48,
        /// <summary>
        /// 0x31
        /// </summary>
        WrBit=49,
        /// <summary>
        /// 0x02
        /// </summary>
        DmBit=2,
        /// <summary>
        /// 0xB0
        /// </summary>
        CioWord=176,
        /// <summary>
        /// 0xB1
        /// </summary>
        WrWord=177,
        /// <summary>
        /// 0x82
        /// </summary>
        DmWord=133
    }
    class FinsTcpPackage
    {
        public FinsTcpType TcpType { get; set; }
        public int ClientAddress { get; set; }
        public int ServerAddress { get; set; }
        public string ResponseStatus { get; set; }
        public FinsCommandType CommandType { get; set; }
        public FinsMemoryArea Area { get; set; }

    }
    class FinsPackageEncoder : IPackageEncoder<FinsTcpPackage>
    {
        public int Encode(IBufferWriter<byte> writer, FinsTcpPackage pack)
        {
            if (pack.TcpType==FinsTcpType.Request)
            {
                writer.Write(new ReadOnlySpan<byte>(new byte[] { 0x46, 0x49, 0x4E, 0x53,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }));
                writer.Write(new ReadOnlySpan<byte>(BitConverter.GetBytes(pack.ClientAddress)));
                return 0;
            }
            else
            {
                //writer.Write(new ReadOnlySpan<byte>(new byte[] { 0x46,0x49,0x4E,0x53,}))
                return 0;
            }
        }
    }

    class FinsTcpPackageFilter : FixedHeaderPipelineFilter<FinsTcpPackage>
    {
        public FinsTcpPackageFilter():base(16)
        {

        }
        protected override int GetBodyLengthFromHeader(ref ReadOnlySequence<byte> buffer)
        {
            var reader = new SequenceReader<byte>(buffer);
            reader.Advance(4);
            reader.TryReadBigEndian(out int length);
            reader.Advance(8);
            return length;
        }
        protected override FinsTcpPackage DecodePackage(ref ReadOnlySequence<byte> buffer)
        {
            var package = new FinsTcpPackage();
            var reader = new SequenceReader<byte>(buffer);
            reader.Advance(4);
            reader.TryReadBigEndian(out int tcpType);
            package.TcpType = (FinsTcpType)tcpType;
            reader.TryReadBigEndian(out int responseCode);
            package.ResponseStatus = StatusCodes.FinsStatusCode[responseCode];
            if (package.TcpType==FinsTcpType.Response)
            {
                reader.TryReadBigEndian(out int clientAddress);
                package.ClientAddress = clientAddress;
                reader.TryReadBigEndian(out int serverAddress);
                package.ServerAddress = serverAddress;
            }
            else if (package.TcpType==FinsTcpType.Work)
            {
                reader.TryReadBigEndian(out int cmdType);
                package.CommandType =(FinsCommandType)cmdType;

            }
            return package;

        }
    }
}
